package com.zh.freechat.domain.user.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zh.freechat.assemble.ChatUserWrapper;
import com.zh.freechat.common.req.param.UserParam;
import com.zh.freechat.common.req.ChatUserForm;
import com.zh.freechat.common.resp.ChatUserVO;
import com.zh.freechat.domain.user.UserStatus;
import com.zh.freechat.domain.user.entity.ChatUser;
import com.zh.freechat.domain.user.repository.UserContactRepository;
import com.zh.freechat.domain.user.repository.UserRepository;
import com.zh.freechat.domain.user.repository.query.UserConditionStrategy;
import com.zh.webcommon.common.auth.LoginUserHolder;
import com.zh.webcommon.common.exception.NotFoundException;
import com.zh.webcommon.common.exception.ServiceException;
import com.zh.webcommon.common.exception.errorcode.BizError;
import com.zh.webcommon.common.support.CopyFieldUtil;
import com.zh.webcommon.upload.FileUploadClient;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.zh.freechat.domain.user.UserStatus.USER_ACTIVE;
import static com.zh.freechat.domain.user.entity.ChatUser.UID_PREFIX;
import static com.zh.mycommon.value.RegexpConst.REGEX_EMAIL;
import static com.zh.mycommon.value.RegexpConst.REGEX_PHONE;
import static com.zh.mycommon.viewdata.ToWrapper.foreach;
import static com.zh.webcommon.common.param.CommonParam.stringPretty;

/**
 * 用户账号service
 *
 * @author ZH
 * @date 10:47 2021/7/16
 */
@Slf4j
@AllArgsConstructor
@Service
public class ChatUserService {
    private final UserRepository userRepository;
    private final UserContactRepository userContactRepository;
    private final PasswordEncoder passwordEncoder;
    private final FileUploadClient uploadClient;

    public String addUser(ChatUserForm form) {
        //判断是否被占用
        String identity = StringUtils.hasText(form.getEmail()) ? form.getEmail() : form.getPhone();
        if (isOccupy(identity)) {
            log.info("{} 被占用,无法添加新user", identity);
            throw new IllegalArgumentException((StringUtils.hasText(form.getEmail()) ? "邮箱" : "手机号") + "被占用,注册账号失败");
        }

        //创建新的user对象
        ChatUser newUser = ChatUserWrapper.wrapper(form);
        newUser.generateAvatar(uploadClient);
        newUser.encodePassword(passwordEncoder);
        //检查uid是否被占用
        while (isOccupy(newUser.getUid())) {
            newUser.generateUid();
        }

        userRepository.insert(newUser);
        return newUser.getUid();
    }

    public void removeUser(String id) {
        userRepository.deleteById(id);
    }

    public void freezeUser(String id) {
        userRepository.updateStatus(id, UserStatus.USER_INACTIVE.getCode());
    }

    public void activeUser(String id) {
        userRepository.updateStatus(id, USER_ACTIVE.getCode());
    }

    public void editPassword(String id, String password, String oldPassword) {
        if (checkOldPassword(id, password, oldPassword))
            throw new ServiceException(BizError.DEFAULT_ERROR, "原密码错误，无法更新密码");

        var update = new ChatUser(id);
        update.setPassword(passwordEncoder.encode(password));

        userRepository.updateById(update);
    }

    public void editAvatar(String id, String avatarUrl) {

        var update = new ChatUser(id);
        update.setAvatarUrl(avatarUrl);

        userRepository.updateById(update);
    }

    public void editPhone(String id, String phone) {
        var update = new ChatUser(id);
        update.setPhone(phone);
        userRepository.updateById(update);
    }

    public void editProfile(String id, String text) {
        var update = new ChatUser(id);
        update.setProfile(text);
        userRepository.updateById(update);
    }

    public void updateUser(String id, ChatUserForm form) {
        ChatUser chatUser = userRepository.selectById(id);
        CopyFieldUtil.copyPropertiesIgnoreNull(form, chatUser);
        userRepository.updateById(chatUser);
    }

    public ChatUser findById(String id) {
        return Optional.ofNullable(userRepository.selectById(id))
                .orElseThrow(() -> new NotFoundException("找不到id=" + id + "的用户"));
    }

    public List<ChatUser> findByIds(List<String> ids) {
        if (ids.isEmpty()) return new ArrayList<>(0);
        return userRepository.selectByIds(ids);
    }

    public ChatUser findByUid(String uid) {
        ChatUser chatUser = userRepository.selectById(uid);
        if (chatUser == null)
            throw new NotFoundException("找不到uid=" + uid + "的用户");
        return chatUser;
    }

    public ChatUser findByUsername(String username) {
        var query = new LambdaQueryWrapper<ChatUser>()
                .eq(ChatUser::getUsername, stringPretty(username));
        ChatUser chatUser = userRepository.selectOne(query);
        if (chatUser == null)
            throw new NotFoundException("找不到username=" + username + "的用户");
        return chatUser;
    }

    public ChatUser findByPhone(String phone) {
        var query = new LambdaQueryWrapper<ChatUser>()
                .eq(ChatUser::getPhone, stringPretty(phone));
        ChatUser chatUser = userRepository.selectOne(query);
        if (chatUser == null)
            throw new NotFoundException("找不到phone=" + phone + "的用户");
        return chatUser;
    }

    public ChatUser findByEmail(String email) {
        var query = new LambdaQueryWrapper<ChatUser>()
                .eq(ChatUser::getEmail, stringPretty(email));
        ChatUser chatUser = userRepository.selectOne(query);

        if (chatUser == null)
            throw new NotFoundException("找不到email=" + email + "的用户");
        return chatUser;
    }

    public List<ChatUser> findByUsernameLike(String account) {
        var query = new LambdaQueryWrapper<ChatUser>()
                .like(ChatUser::getUsername, stringPretty(account));
        return userRepository.selectList(query);
    }

    /**
     * 手机号或邮箱号或username是否被占用
     *
     * @param str
     * @return
     */
    public Boolean isOccupy(String str) {
        var query = new LambdaQueryWrapper<ChatUser>();
        //条件
        if (str.matches(REGEX_PHONE)) {
            query.eq(ChatUser::getPhone, str);
        } else if (str.matches(REGEX_EMAIL)) {
            query.eq(ChatUser::getEmail, str);
        } else if (str.startsWith("ch") ||str.startsWith(UID_PREFIX)) {
            query.eq(ChatUser::getUid, str);
        } else {
            query.eq(ChatUser::getUsername, str);
        }
        long count = userRepository.selectCount(query);
        return count > 0;
    }

    /**
     * 搜索用户
     * 根据手机号，邮箱，或username，或昵称
     *
     * @param kw
     * @param direct true直接根据Uid搜索
     * @return
     */
    public List<ChatUserVO> searchChatUserByKeyword(String kw, boolean direct) {

        List<ChatUser> chatUsers = new LinkedList<>();
        if (direct || kw.startsWith(UID_PREFIX)) {
            log.debug("search chatUser by uid：{}", kw);
            chatUsers.add(this.findByUid(kw));
        } else if (kw.matches(REGEX_PHONE)) {
            log.debug("search chatUser by phone：{}", kw);
            chatUsers.add(this.findByPhone(kw));
        } else if (kw.matches(REGEX_EMAIL)) {
            log.debug("search chatUser by email：{}", kw);
            chatUsers.add(this.findByEmail(kw));
        } else {
            log.debug("search chatUser like username：{}", kw);
            chatUsers.addAll(this.findByUsernameLike(kw));
        }
        log.debug("search result: all count = {}", chatUsers.size());

        //过滤掉status，留下正常状态的users
        List<ChatUser> users = chatUsers.stream()
                .filter(e -> UserStatus.toStatus(e.getStatus()) == USER_ACTIVE)
                .toList();

        var userIds = foreach(users, ChatUser::getUid);

        Map<String, Long> relIdByUserIdsMap;
        if (direct) {
            relIdByUserIdsMap = userContactRepository.getRelIdByUserIds(userIds, LoginUserHolder.currentUserId());
        } else {
            relIdByUserIdsMap = Map.of();
        }

        return foreach(chatUsers, (u -> {
            var userVo = ChatUserWrapper.convertVO(u);
            if (direct) {
                userVo.setRelId(Optional.ofNullable(relIdByUserIdsMap.get(u.getUid())).map(Object::toString).orElse(null));
            }
            return userVo;
        }));
    }

    /**
     * 验证原密码是否正确
     *
     * @param userId
     * @param password
     * @param oldpassword
     * @return
     */
    private boolean checkOldPassword(String userId, String password, String oldpassword) {
        if (password.equals(oldpassword)) {
            throw new ServiceException(BizError.DEFAULT_ERROR, "原密码和新密码相同，无法更新密码");
        }
        ChatUser user = findById(userId);
        return passwordEncoder.matches(oldpassword, user.getPassword());
    }

    /**
     * 分页查询 服务商品
     *
     * @param param
     * @return
     */
    public Page<ChatUser> findPage(UserParam param) {
        Page<ChatUser> page = new Page<>(param.getNum(), param.getSize());
        var queryWrapper = UserConditionStrategy.get().getQueryWrapper(param);
        return userRepository.selectPage(page, queryWrapper);
    }
}
